#[[
IO分为了两种
    * stdio(标准IO)
    * sysio(系统调用IO/系统IO/文件IO)

IO操作是一切实现的基础。

优先使用标准IO。不过在linux下, 使用系统调用IO也没有问题。因为我写的程序
就是只运行在linux平台上, 不考虑移植性。


标准IO依赖于系统调用IO来实现的。

]]

#[[
标准IO

FILE 类型贯穿始终。FILE是一个结构体类型。

fopen();

FOPEN(3)                                                          Linux Programmer's Manual                                                          FOPEN(3)

NAME
       fopen, fdopen, freopen - stream open functions
       流打开函数, 打开一个流。

SYNOPSIS
       #include <stdio.h>

       // 打开一个文件, pathname: 打开哪个文件, 可以是绝对路径, 也可以是相对路径。
       // mode: 以什么方式打开这个文件。
       // 返回一个指向 FILE 结构体的指针。
       FILE *fopen(const char *pathname, const char *mode);

       FILE *fdopen(int fd, const char *mode);

       FILE *freopen(const char *pathname, const char *mode, FILE *stream);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
   glibc 的功能测试宏要求（请参阅 feature_test_macros(7)）:

       fdopen(): _POSIX_C_SOURCE

DESCRIPTION
       The fopen() function opens the file whose name is the string pointed to by pathname and associates a stream with it.
       fopen() 函数打开名称为 pathname 指向的字符串的文件，并将流与其关联。

       The argument mode points to a string beginning with one of the following sequences (possibly followed by additional characters, as described below):
       参数 mode 指向以以下序列之一开头的字符串（可能后跟附加字符，如下所述）:

       r      Open text file for reading.  The stream is positioned at the beginning of the file.
       r      打开文本文件进行读取。流位于文件的开头。
              以只读形式打开文件, 当前的文件指针被定位到文件的开始处。

       r+     Open for reading and writing.  The stream is positioned at the beginning of the file.
              打开读取和写入。流位于文件的开头。
              以读写形式打开文件, 当前的文件指针被定位到文件的开始处。

       w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.
              将文件截断为零长度或创建用于写入的文本文件。流位于文件的开头。
              将文件截断为0长度或者以只写的形式创建一个文件, 文件指针被定位到文件的开始处(文件的开始处是文件当中第一个有效字符。)。
              其实就是有则清空, 无则创建。

       w+     Open  for reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The stream is positioned at the beginning
              of the file.
              打开读取和写入。如果文件不存在，则创建该文件，否则将被截断。流位于文件的开头。
              以读写形式打开一个文件, 如果文件不存在则创建这个文件, 否则将这个文件截短为0长度。
              其实就是以读写形式打开一个文件, 这个文件有则清空, 无则创建。
              文件指针被定位到文件的开始处。

       a      Open for appending (writing at end of file).  The file is created if it does not exist.  The stream is positioned at the end of the file.
              打开以追加（在文件末尾写入）。如果文件不存在，则创建该文件。流位于文件的末尾。
              以追加只写的形式打开一个文件。如果文件不存在, 则创建这个文件。
              流的文件位置指针被定位到文件的结尾处。
              end of file(EOF) 有两种选择:
              1. 文件的最后一个有效字节
              2. 文件的最后一个有效字节的下一个位置。
              EOF是文件的最后一个有效字节的下一个位置。

              writing at end of file(在EOF处开始写。)所以EOF一定是当前文件的
              最后一个有效字节的下一个位置。

              读写是都发生到 当前位置 , 如果EOF是文件的最后一个字节的话, 那么写就是发生在
              EOF的, 会覆盖掉文件的最后一个字节。所以, EOF是文件最后一个字节的下一个位置。
              这和C++的前闭后开区间相似。

       a+     Open for reading and appending (writing at end of file).  The file is created if it does not exist.  Output is always appended to  the  end  of
              the  file.   POSIX is silent on what the initial read position is when using this mode.  For glibc, the initial file position for reading is at
              the beginning of the file, but for Android/BSD/MacOS, the initial file position for reading is at the end of the file.
              打开以进行读取和追加（在文件末尾写入）。如果文件不存在，则创建该文件。输出总是附加到文件的末尾。
              POSIX 对使用此模式时的初始读取位置保持沉默。
              对于glibc，读取的初始文件位置在文件的开头，
              但对于Android/BSD/MacOS，读取的初始文件位置在文件的末尾。

              以读写形式追加打开文件(文件不存在会创建一个), 但是读的文件位置指针和写的文件位置指针是不同的,
              写: writing at end of file.
              读: 在glic中, 读的文件位置指针放在了 reading at the beginning of the file. 而对于Android/BSD/MacOS，读取的初始文件位置在EOF。

        有6种操作文件的方式, r r+ w w+ a a+ 。
        这6种方式中只有 r 和 r+ 如果文件不存在, 不会创建文件, 其它四种都是如果没有文件就会创建文件。
        所以 r 和 r+ 要求文件必须存在, 如果文件不存在, 当前调用结束, 返回出错。



       The mode string can also include the letter 'b' either as a last character or as a character between  the  characters  in  any  of  the  two-character
       strings described above.  This is strictly for compatibility with C89 and has no effect; the 'b' is ignored on all POSIX conforming systems, including
       Linux.  (Other systems may treat text files and binary files differently, and adding the 'b' may be a good idea if you do I/O to a binary file and ex‐
       pect that your program may be ported to non-UNIX environments.)
       模式字符串还可以包括字母“b”作为最后一个字符或作为上述任何两个字符串中的字符之间的字符。
       这严格是为了兼容 C89，没有任何影响； 'b' 在所有符合 POSIX 的系统上都被忽略，包括 Linux。
       （其他系统可能会以不同的方式对待文本文件和二进制文件，如果您对二进制文件进行 IO 操作并希望您的程序可以移植到非 UNIX 环境中，那么添加“b”可能是个好主意。）

       r rb r+ r+b
       所有遵循 POSIX 的系统中 b 被忽略。因为 POSIX 只有一个概念 流。
       POSIX不区分文本文件和二进制文件。而windows下文件分为了文本文件和二进制文件, 所以如果在linux写好的程序移植到windows下, 添加 b 会是一个好主意。


       See NOTES below for details of glibc extensions for mode.
       有关模式的 glibc 扩展的详细信息，请参阅下面的注释。

       Any  created  file  will have the mode S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666), as modified by the process's umask value (see
       umask(2)).
       任何创建的文件都将具有模式 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666)，由进程的 umask 值修改（请参阅 umask(2)）。

       Reads and writes may be intermixed on read/write streams in any order.  Note that ANSI C requires that a file positioning function  intervene  between
       output  and  input,  unless  an input operation encounters end-of-file.  (If this condition is not met, then a read is allowed to return the result of
       writes other than the most recent.)  Therefore it is good practice (and indeed sometimes necessary under Linux) to put an fseek(3) or fgetpos(3) oper‐
       ation between write and read operations on such a stream.  This operation may be an apparent no-op (as in fseek(..., 0L, SEEK_CUR) called for its syn‐
       chronizing side effect).
       读取和写入可以以任何顺序混合在读写流上。请注意，ANSI C 要求文件定位函数在输出和输入之间进行干预，除非输入操作遇到文件结束。
       （如果不满足此条件，则允许读取返回除最近写入之外的写入结果。）因此，将 fseek(3) 或 fgetpos(3) ) 对此类流的写入和读取操作之间的操作。
       这个操作可能是一个明显的空操作（如在 fseek(..., 0L, SEEK_CUR) 中调用它的同步副作用）。

       Opening a file in append mode (a as the first character of mode) causes all subsequent write operations to this stream to occur at end-of-file, as  if
       preceded the call:
       在追加模式下打开文件（a 作为模式的第一个字符）会导致对该流的所有后续写入操作发生在文件末尾，就像在调用之前一样:

           fseek(stream, 0, SEEK_END);

       The file descriptor associated with the stream is opened as if by a call to open(2) with the following flags:
       与流关联的文件描述符被打开，就像通过调用 open(2) 并带有以下标志一样:

              ┌─────────────┬───────────────────────────────┐
              │fopen() mode │ open() flags                  │
              ├─────────────┼───────────────────────────────┤
              │     r       │ O_RDONLY                      │
              ├─────────────┼───────────────────────────────┤
              │     w       │ O_WRONLY | O_CREAT | O_TRUNC  │
              ├─────────────┼───────────────────────────────┤
              │     a       │ O_WRONLY | O_CREAT | O_APPEND │
              ├─────────────┼───────────────────────────────┤
              │     r+      │ O_RDWR                        │
              ├─────────────┼───────────────────────────────┤
              │     w+      │ O_RDWR | O_CREAT | O_TRUNC    │
              ├─────────────┼───────────────────────────────┤
              │     a+      │ O_RDWR | O_CREAT | O_APPEND   │
              └─────────────┴───────────────────────────────┘
   fdopen()
       The fdopen() function associates a stream with the existing file descriptor, fd.  The mode of the stream (one of the values "r", "r+", "w", "w+", "a",
       "a+") must be compatible with the mode of the file descriptor.  The file position indicator of the new stream is set to that belonging to fd, and  the
       error  and end-of-file indicators are cleared.  Modes "w" or "w+" do not cause truncation of the file.  The file descriptor is not dup'ed, and will be
       closed when the stream created by fdopen() is closed.  The result of applying fdopen() to a shared memory object is undefined.
       fdopen() 函数将流与现有文件描述符 fd 相关联。流的模式（值“r”、“r+”、“w”、“w+”、“a”、“a+”之一）必须与文件描述符的模式兼容。
       新流的文件位置指示符设置为属于 fd 的文件位置指示符，并清除错误和文件结束指示符。
       模式“w”或“w+”不会导致文件截断。文件描述符不会被复制，并且会在 fdopen() 创建的流关闭时关闭。
       将 fdopen() 应用于共享内存对象的结果未定义。

   freopen()
       The freopen() function opens the file whose name is the string pointed to by pathname and associates the stream pointed to by  stream  with  it.   The
       original stream (if it exists) is closed.  The mode argument is used just as in the fopen() function.
       freopen() 函数打开名称为 pathname 指向的字符串的文件，并将 stream 指向的流与其关联。原始流（如果存在）已关闭。
       mode 参数的使用就像在 fopen() 函数中一样。

       If  the  pathname argument is a null pointer, freopen() changes the mode of the stream to that specified in mode; that is, freopen() reopens the path‐
       name that is associated with the stream.  The specification for this behavior was added in the C99 standard, which says:
       如果 pathname 参数是空指针，则 freopen() 将流的模式更改为 mode; 中指定的       模式；也就是说，freopen() 重新打开与流关联的路径名。
       在 C99 标准中添加了此行为的规范，其中说:

              In this case, the file descriptor associated with the stream need not be closed if the call to freopen() succeeds.   It  is  implementation-de‐
              fined which changes of mode are permitted (if any), and under what circumstances.
              在这种情况下，如果对 freopen() 的调用成功，则不需要关闭与流关联的文件描述符。实现定义允许哪些模式更改（如果有），以及在什么情况下。

       The primary use of the freopen() function is to change the file associated with a standard text stream (stderr, stdin, or stdout).
       freopen() 函数的主要用途是更改与标准文本流（stderr、stdin 或 stdout）关联的文件。

RETURN VALUE
       Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer.  Otherwise, NULL is returned and errno is set to indicate the error.
       成功完成 fopen() 后，fdopen() 和 freopen() 返回一个 FILE 指针。否则，返回 NULL 并设置 errno 以指示错误。

       errno在 /usr/include/asm-generic/errno-base.h 和
              /usr/include/asm-generic/errno.h
              这两个头文件中宏定义。

ERRORS
       EINVAL The mode provided to fopen(), fdopen(), or freopen() was invalid.
       EINVAL 提供给 fopen()、fdopen() 或 freopen() 的模式无效。

       The fopen(), fdopen() and freopen() functions may also fail and set errno for any of the errors specified for the routine malloc(3).
       fopen()、fdopen() 和 freopen() 函数也可能失败并为例程 malloc(3) 指定的任何错误设置 errno。

       The fopen() function may also fail and set errno for any of the errors specified for the routine open(2).
       fopen() 函数也可能失败并为例程 open(2) 指定的任何错误设置 errno。

       The fdopen() function may also fail and set errno for any of the errors specified for the routine fcntl(2).
       fdopen() 函数也可能失败并为例程 fcntl(2) 指定的任何错误设置 errno。

       The freopen() function may also fail and set errno for any of the errors specified for the routines open(2), fclose(3), and fflush(3).
       freopen() 函数也可能失败并为例程 open(2)、fclose(3) 和 fflush(3) 指定的任何错误设置 errno。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).
       有关本节中使用的术语的解释，请参阅 attributes(7)。

       ┌─────────────────────────────┬───────────────┬─────────┐
       │Interface                    │ Attribute     │ Value   │
       ├─────────────────────────────┼───────────────┼─────────┤
       │fopen(), fdopen(), freopen() │ Thread safety │ MT-Safe │
       └─────────────────────────────┴───────────────┴─────────┘
CONFORMING TO(符合)
       fopen(), freopen(): POSIX.1-2001, POSIX.1-2008, C89, C99.

       fdopen(): POSIX.1-2001, POSIX.1-2008.

NOTES
   Glibc notes
       The GNU C library allows the following extensions for the string specified in mode:
       GNU C 库允许对 mode 中指定的字符串进行以下扩展:

       c (since glibc 2.3.3)
              Do not make the open operation, or subsequent read and write operations, thread cancellation points.  This flag is ignored for fdopen().
              不要做open操作，或者后续的读写操作，线程取消点。 fdopen() 忽略此标志。

       e (since glibc 2.7)
              Open the file with the O_CLOEXEC flag.  See open(2) for more information.  This flag is ignored for fdopen().
              打开带有 O_CLOEXEC 标志的文件。有关更多信息，请参阅 open(2)。 fdopen() 忽略此标志。

       m (since glibc 2.3)
              Attempt  to access the file using mmap(2), rather than I/O system calls (read(2), write(2)).  Currently, use of mmap(2) is attempted only for a
              file opened for reading.
              尝试使用 mmap(2) 而不是 IO 系统调用（read(2), write(2)）访问文件。目前，仅对打开用于读取的文件尝试使用 mmap(2)。

       x      Open the file exclusively (like the O_EXCL flag of open(2)).  If the file already exists, fopen() fails, and sets errno to EEXIST.   This  flag
              is ignored for fdopen().
              以独占方式打开文件（如 open(2) 的 O_EXCL 标志）。如果文件已经存在，fopen() 会失败，并将 errno 设置为 EEXIST。 fdopen() 忽略此标志。

       In addition to the above characters, fopen() and freopen() support the following syntax in mode:
       除上述字符外，fopen() 和 freopen() 在模式下支持以下语法:

           ,ccs=string

       The  given  string is taken as the name of a coded character set and the stream is marked as wide-oriented.  Thereafter, internal conversion functions
       convert I/O to and from the character set string.  If the ,ccs=string syntax is not specified, then the wide-orientation of the stream  is  determined
       by  the  first  file  operation.  If that operation is a wide-character operation, the stream is marked wide-oriented, and functions to convert to the
       coded character set are loaded.
       给定的字符串作为编码字符集的名称，并且流被标记为面向宽的。此后，内部转换函数将 IO 与字符集字符串相互转换。
       如果未指定 ,ccs=string 语法，则流的宽方向由第一个文件操作确定。
       如果该操作是宽字符操作，则将流标记为面向宽字符，并加载转换为编码字符集的函数。

BUGS
       When parsing for individual flag characters in mode (i.e., the characters preceding the "ccs" specification), the glibc implementation of fopen()  and
       freopen()  limits  the  number  of characters examined in mode to 7 (or, in glibc versions before 2.14, to 6, which was not enough to include possible
       specifications such as "rb+cmxe").  The current implementation of fdopen() parses at most 5 characters in mode.
       在解析 mode 中的单个标志字符时（即“ccs”规范之前的字符），
       fopen() 和 freopen() 的 glibc 实现将 mode 中检查的字符数限制为 7（或者，在 2.14 之前的 glibc 版本中） , 到 6，
       这不足以包含可能的规范，例如“rb+cmxe”）。 fdopen() 的当前实现在 mode 中最多解析 5 个字符。

SEE ALSO(参见)
       open(2), fclose(3), fileno(3), fmemopen(3), fopencookie(3), open_memstream(3)

COLOPHON(版权)
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

GNU                                                                       2019-05-09                                                                 FOPEN(3)



fclose();

FCLOSE(3)                                                         Linux Programmer's Manual                                                         FCLOSE(3)

NAME
       fclose - close a stream
       关闭一个流。

SYNOPSIS
       #include <stdio.h>

       int fclose(FILE *stream);

DESCRIPTION
       The  fclose()  function  flushes the stream pointed to by stream (writing any buffered output data using fflush(3)) and closes the underlying file de‐
       scriptor.
       fclose() 函数刷新流指向的流（使用 fflush(3) 写入任何缓冲的输出数据）并关闭底层文件描述符。

       The behaviour of fclose() is undefined if the stream parameter is an illegal pointer, or is a descriptor already passed to a  previous  invocation  of
       fclose().
       如果流参数是非法指针，或者是已传递给先前调用 fclose() 的描述符，则 fclose() 的行为未定义。

RETURN VALUE
       Upon  successful  completion,  0  is returned.  Otherwise, EOF is returned and errno is set to indicate the error.  In either case, any further access
       (including another call to fclose()) to the stream results in undefined behavior.
       成功完成后，返回 0。否则，返回 EOF 并设置 errno 以指示错误。
       在任何一种情况下，对流的任何进一步访问（包括对 fclose() 的另一次调用）都会导致未定义的行为。

       一般情况下, fclose();的返回值很少去检验, 因为我们认为这个函数调用不会失败。
       EOF是#define出来的一个宏值, 一般情况下是-1, 所以慎用宏值, 而使用宏名,
       只有有宏名就用宏名, 不要用宏值。


ERRORS
       EBADF  The file descriptor underlying stream is not valid.
       EBADF 底层流的文件描述符无效。

       The fclose() function may also fail and set errno for any of the errors specified for the routines close(2), write(2), or fflush(3).
       fclose() 函数也可能失败并为例程 close(2)、write(2) 或 fflush(3) 指定的任何错误设置 errno。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).
       有关本节中使用的术语的解释，请参阅 attributes(7)。

       ┌──────────┬───────────────┬─────────┐
       │Interface │ Attribute     │ Value   │
       ├──────────┼───────────────┼─────────┤
       │fclose()  │ Thread safety │ MT-Safe │
       └──────────┴───────────────┴─────────┘

CONFORMING TO(符合)
       POSIX.1-2001, POSIX.1-2008, C89, C99.

NOTES
       Note that fclose() flushes only the user-space buffers provided by the C library.  To ensure that the data is physically stored  on  disk  the  kernel
       buffers must be flushed too, for example, with sync(2) or fsync(2).
       请注意， fclose() 仅刷新 C 库提供的用户空间缓冲区。为了确保数据物理存储在磁盘上，内核缓冲区也必须刷新，例如，使用 sync(2) 或 fsync(2)。

SEE ALSO(参见)
       close(2), fcloseall(3), fflush(3), fileno(3), fopen(3), setbuf(3)

COLOPHON(版权)
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

GNU                                                                       2016-12-12                                                                FCLOSE(3)







fgetc();
fputc();

fgets();
fputs();

fread();
fwrite();

printf();
scanf();

fseek();
ftell();
rewind();

fflush();

]]

add_executable(IO-fopen1 IO-fopen1.cpp)
add_executable(IO-fopen2 IO-fopen2.cpp)
#[[
在一个进程中使用 fopen(); 打开的文件一定是有一个上限的。是资源一定有上限。
]]
add_executable(IO-fopen3 IO-fopen3.cpp)

#[[
实现一个 MyCopy。

liuyou@liuyou-virtual-machine:~/CLionProjects/LinuxEnvironmentProgramming2/src/io$ diff /etc/services testTmp
liuyou@liuyou-virtual-machine:~/CLionProjects/LinuxEnvironmentProgramming2/src/io$ ll
总用量 88
drwxrwxr-x 2 liuyou liuyou  4096 10月 26 14:18 ./
drwxrwxr-x 5 liuyou liuyou  4096 10月 26 10:40 ../
-rwxrwxr-x 1 liuyou liuyou 17688 10月 26 14:17 a.out*
-rw-rw-r-- 1 liuyou liuyou 25555 10月 26 14:27 CMakeLists.txt
-rw-rw-r-- 1 liuyou liuyou   874 10月 26 13:38 IO-fopen1.cpp
-rw-rw-r-- 1 liuyou liuyou   782 10月 26 13:39 IO-fopen2.cpp
-rw-rw-r-- 1 liuyou liuyou  3845 10月 26 14:02 IO-fopen3.cpp
-rw-rw-r-- 1 liuyou liuyou   867 10月 26 14:25 IO-MyCopy1.cpp
# 14464 是这个文件的大小, 多少个字节数, 多少个字符个数。
-rw-rw-r-- 1 liuyou liuyou 14464 10月 26 14:18 testTmp
liuyou@liuyou-virtual-machine:~/CLionProjects/LinuxEnvironmentProgramming2/src/io$

通过 fgetc()和fputc() 来实现了 mycopy。
]]
add_executable(IO-MyCopy1 IO-MyCopy1.cpp)
#[[
测试文件有多少个有效字符个数, 即文件有多少个字节数, 文件的大小。
]]
add_executable(IO-CalculateFileSize1 IO-CalculateFileSize1.cpp)
#[[
使用 fgets(); 来重构之前 MyCopy。
]]
add_executable(IO-MyCopy2 IO-MyCopy2.cpp)
#[[
FREAD(3)                                                          Linux Programmer's Manual                                                          FREAD(3)

NAME
       fread, fwrite - binary stream input/output
       二进制流的输入输出。在linux中不区分二进制流和文本流, 都是一样的, 都是流。

SYNOPSIS
       #include <stdio.h>


       size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);


       size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);


       使用 fread 和 fwrite 永远使用 单字节来使用, 即
       fread(buf, 1, 10, fp);
       fwrite(buf, 1, 10, fp);
       也就是把 fread()和fwrite() 当做 fgetc()和fputc() 来使用。





DESCRIPTION
       The function fread() reads nmemb items of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.
       函数 fread() 从 stream 指向的流中读取 nmemb 数据项，每个 size 字节长，并将它们存储在 ptr 给定的位置。

       The  function fwrite() writes nmemb items of data, each size bytes long, to the stream pointed to by stream, obtaining them from the location given by
       ptr.
       函数 fwrite() 将 nmemb 数据项（每个 size 字节长）写入 stream 指向的流，从 ptr 给定的位置获取它们。

       For nonlocking counterparts, see unlocked_stdio(3).
       对于非锁定对应项，请参阅 unlocked_stdio(3)。

RETURN VALUE
       On success, fread() and fwrite() return the number of items read or written.  This number equals the number of bytes transferred only when size is  1.
       If an error occurs, or the end of the file is reached, the return value is a short item count (or zero).
       成功时， fread() 和 fwrite() 返回读取或写入的项目数。此数字等于仅当 size 为 1 时传输的字节数。如果发生错误或到达文件末尾，则返回值是一个短项目计数（或零）。

       fread() does not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred.
       fread() 不区分文件结束和错误，调用者必须使用 feof(3) 和 ferror(3) 来确定发生了什么。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).
       有关本节中使用的术语的解释，请参阅 attributes(7)。

       ┌──────────────────┬───────────────┬─────────┐
       │Interface         │ Attribute     │ Value   │
       ├──────────────────┼───────────────┼─────────┤
       │fread(), fwrite() │ Thread safety │ MT-Safe │
       └──────────────────┴───────────────┴─────────┘
CONFORMING TO
       POSIX.1-2001, POSIX.1-2008, C89.

SEE ALSO
       read(2), write(2), feof(3), ferror(3), unlocked_stdio(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

GNU                                                                       2015-07-23                                                                 FREAD(3)

]]
#[[
使用 fread()和fwrite() 来重构之前的 MyCopy。
]]
add_executable(IO-MyCopy3 IO-MyCopy3.cpp)

#[[
PRINTF(3)                                                                       Linux Programmer's Manual                                                                       PRINTF(3)

NAME
       printf, fprintf, dprintf, sprintf, snprintf, vprintf, vfprintf, vdprintf, vsprintf, vsnprintf - formatted output conversion

SYNOPSIS
       #include <stdio.h>

       // printf(..., ...); 相当于 fprintf(stdout, ..., ...);
       int printf(const char *format, ...);
       // 下面的这几个函数要比 printf();更加的实用。
       int fprintf(FILE *stream, const char *format, ...);
       int dprintf(int fd, const char *format, ...);

       // 这个函数非常好用, 另外一个函数是 atoi(); atoi把一个字符串转换成一个整形数。
       int sprintf(char *str, const char *format, ...);
       int snprintf(char *str, size_t size, const char *format, ...);

       #include <stdarg.h>

       int vprintf(const char *format, va_list ap);
       int vfprintf(FILE *stream, const char *format, va_list ap);
       int vdprintf(int fd, const char *format, va_list ap);
       int vsprintf(char *str, const char *format, va_list ap);
       int vsnprintf(char *str, size_t size, const char *format, va_list ap);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       snprintf(), vsnprintf():
           _XOPEN_SOURCE >= 500 || _ISOC99_SOURCE ||
               || /* Glibc versions <= 2.19: */ _BSD_SOURCE

       dprintf(), vdprintf():
           Since glibc 2.10:
               _POSIX_C_SOURCE >= 200809L
           Before glibc 2.10:
               _GNU_SOURCE

DESCRIPTION
       The  functions  in  the printf() family produce output according to a format as described below.  The functions printf() and vprintf() write output to stdout, the standard output
       stream; fprintf() and vfprintf() write output to the given output stream; sprintf(), snprintf(), vsprintf() and vsnprintf() write to the character string str.

       The function dprintf() is the same as fprintf() except that it outputs to a file descriptor, fd, instead of to a stdio stream.

       The functions snprintf() and vsnprintf() write at most size bytes (including the terminating null byte ('\0')) to str.

       The functions vprintf(), vfprintf(), vdprintf(), vsprintf(), vsnprintf() are equivalent to the functions printf(), fprintf(), dprintf(), sprintf(), snprintf(), respectively,  ex‐
       cept  that  they  are  called  with a va_list instead of a variable number of arguments.  These functions do not call the va_end macro.  Because they invoke the va_arg macro, the
       value of ap is undefined after the call.  See stdarg(3).

       All of these functions write the output under the control of a format string that specifies how subsequent arguments (or arguments accessed via the variable-length  argument  fa‐
       cilities of stdarg(3)) are converted for output.

       C99  and POSIX.1-2001 specify that the results are undefined if a call to sprintf(), snprintf(), vsprintf(), or vsnprintf() would cause copying to take place between objects that
       overlap (e.g., if the target string array and one of the supplied input arguments refer to the same buffer).  See NOTES.

   Format of the format string
       The format string is a character string, beginning and ending in its initial shift state, if any.  The format string is composed of zero or more directives:  ordinary  characters
       (not  %),  which  are  copied unchanged to the output stream; and conversion specifications, each of which results in fetching zero or more subsequent arguments.  Each conversion
       specification is introduced by the character %, and ends with a conversion specifier.  In between there may be (in this order) zero or  more  flags,  an  optional  minimum  field
       width, an optional precision and an optional length modifier.

       The  arguments  must  correspond  properly (after type promotion) with the conversion specifier.  By default, the arguments are used in the order given, where each '*' (see Field
       width and Precision below) and each conversion specifier asks for the next argument (and it is an error if insufficiently many arguments are given).  One can also specify explic‐
       itly which argument is taken, at each place where an argument is required, by writing "%m$" instead of '%' and "*m$" instead of '*', where the decimal integer m denotes the posi‐
       tion in the argument list of the desired argument, indexed starting from 1.  Thus,

           printf("%*d", width, num);

       and

           printf("%2$*1$d", width, num);

       are equivalent.  The second style allows repeated references to the same argument.  The C99 standard does not include the style using '$', which comes from the Single UNIX Speci‐
       fication.   If the style using '$' is used, it must be used throughout for all conversions taking an argument and all width and precision arguments, but it may be mixed with "%%"
       formats, which do not consume an argument.  There may be no gaps in the numbers of arguments specified using '$'; for example, if arguments 1 and 3 are specified, argument 2 must
       also be specified somewhere in the format string.

       For  some  numeric  conversions a radix character ("decimal point") or thousands' grouping character is used.  The actual character used depends on the LC_NUMERIC part of the lo‐
       cale.  (See setlocale(3).)  The POSIX locale uses '.' as radix character, and does not have a grouping character.  Thus,

               printf("%'.2f", 1234567.89);

       results in "1234567.89" in the POSIX locale, in "1234567,89" in the nl_NL locale, and in "1.234.567,89" in the da_DK locale.

   Flag characters
       The character % is followed by zero or more of the following flags:

       #      The value should be converted to an "alternate form".  For o conversions, the first character of the output string is made zero (by prefixing a 0 if it was  not  zero  al‐
              ready).  For x and X conversions, a nonzero result has the string "0x" (or "0X" for X conversions) prepended to it.  For a, A, e, E, f, F, g, and G conversions, the result
              will always contain a decimal point, even if no digits follow it (normally, a decimal point appears in the results of those conversions only if a digit  follows).   For  g
              and G conversions, trailing zeros are not removed from the result as they would otherwise be.  For other conversions, the result is undefined.

       0      The  value  should  be zero padded.  For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversions, the converted value is padded on the left with zeros rather than blanks.
              If the 0 and - flags both appear, the 0 flag is ignored.  If a precision is given with a numeric conversion (d, i, o, u, x, and X), the 0 flag is ignored.  For other  con‐
              versions, the behavior is undefined.

       -      The  converted  value  is to be left adjusted on the field boundary.  (The default is right justification.)  The converted value is padded on the right with blanks, rather
              than on the left with blanks or zeros.  A - overrides a 0 if both are given.

       ' '    (a space) A blank should be left before a positive number (or empty string) produced by a signed conversion.

       +      A sign (+ or -) should always be placed before a number produced by a signed conversion.  By default, a sign is used only for negative numbers.  A + overrides a  space  if
              both are used.

       The five flag characters above are defined in the C99 standard.  The Single UNIX Specification specifies one further flag character.

       '      For  decimal conversion (i, d, u, f, F, g, G) the output is to be grouped with thousands' grouping characters if the locale information indicates any.  (See setlocale(3).)
              Note that many versions of gcc(1) cannot parse this option and will issue a warning.  (SUSv2 did not include %'F, but SUSv3 added it.)

       glibc 2.2 adds one further flag character.

       I      For decimal integer conversion (i, d, u) the output uses the locale's alternative output digits, if any.  For example, since glibc 2.2.3 this will give Arabic-Indic digits
              in the Persian ("fa_IR") locale.

   Field width
       An optional decimal digit string (with nonzero first digit) specifying a minimum field width.  If the converted value has fewer characters than the field width, it will be padded
       with spaces on the left (or right, if the left-adjustment flag has been given).  Instead of a decimal digit string one may write "*" or "*m$" (for  some  decimal  integer  m)  to
       specify  that the field width is given in the next argument, or in the m-th argument, respectively, which must be of type int.  A negative field width is taken as a '-' flag fol‐
       lowed by a positive field width.  In no case does a nonexistent or small field width cause truncation of a field; if the result of a conversion is wider than the field width, the
       field is expanded to contain the conversion result.

   Precision
       An  optional precision, in the form of a period ('.')  followed by an optional decimal digit string.  Instead of a decimal digit string one may write "*" or "*m$" (for some deci‐
       mal integer m) to specify that the precision is given in the next argument, or in the m-th argument, respectively, which must be of type int.  If the precision is given  as  just
       '.', the precision is taken to be zero.  A negative precision is taken as if the precision were omitted.  This gives the minimum number of digits to appear for d, i, o, u, x, and
       X conversions, the number of digits to appear after the radix character for a, A, e, E, f, and F conversions, the maximum number of significant digits for g and G conversions, or
       the maximum number of characters to be printed from a string for s and S conversions.

   Length modifier
       Here, "integer conversion" stands for d, i, o, u, x, or X conversion.

       hh     A following integer conversion corresponds to a signed char or unsigned char argument, or a following n conversion corresponds to a pointer to a signed char argument.

       h      A following integer conversion corresponds to a short int or unsigned short int argument, or a following n conversion corresponds to a pointer to a short int argument.

       l      (ell)  A following integer conversion corresponds to a long int or unsigned long int argument, or a following n conversion corresponds to a pointer to a long int argument,
              or a following c conversion corresponds to a wint_t argument, or a following s conversion corresponds to a pointer to wchar_t argument.

       ll     (ell-ell).  A following integer conversion corresponds to a long long int or unsigned long long int argument, or a following n conversion corresponds to  a  pointer  to  a
              long long int argument.

       q      A synonym for ll.  This is a nonstandard extension, derived from BSD; avoid its use in new code.

       L      A following a, A, e, E, f, F, g, or G conversion corresponds to a long double argument.  (C99 allows %LF, but SUSv2 does not.)

       j      A following integer conversion corresponds to an intmax_t or uintmax_t argument, or a following n conversion corresponds to a pointer to an intmax_t argument.

       z      A following integer conversion corresponds to a size_t or ssize_t argument, or a following n conversion corresponds to a pointer to a size_t argument.

       Z      A nonstandard synonym for z that predates the appearance of z.  Do not use in new code.

       t      A following integer conversion corresponds to a ptrdiff_t argument, or a following n conversion corresponds to a pointer to a ptrdiff_t argument.

       SUSv3  specifies  all  of the above, except for those modifiers explicitly noted as being nonstandard extensions.  SUSv2 specified only the length modifiers h (in hd, hi, ho, hx,
       hX, hn) and l (in ld, li, lo, lx, lX, ln, lc, ls) and L (in Le, LE, Lf, Lg, LG).

       As a nonstandard extension, the GNU implementations treats ll and L as synonyms, so that one can, for example, write llg (as a synonym for the standards-compliant Lg) and Ld  (as
       a synonym for the standards compliant lld).  Such usage is nonportable.

   Conversion specifiers
       A character that specifies the type of conversion to be applied.  The conversion specifiers and their meanings are:

       d, i   The  int  argument  is  converted  to signed decimal notation.  The precision, if any, gives the minimum number of digits that must appear; if the converted value requires
              fewer digits, it is padded on the left with zeros.  The default precision is 1.  When 0 is printed with an explicit precision 0, the output is empty.

       o, u, x, X
              The unsigned int argument is converted to unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal (x and X) notation.  The letters abcdef are used for x  conver‐
              sions;  the  letters  ABCDEF are used for X conversions.  The precision, if any, gives the minimum number of digits that must appear; if the converted value requires fewer
              digits, it is padded on the left with zeros.  The default precision is 1.  When 0 is printed with an explicit precision 0, the output is empty.

       e, E   The double argument is rounded and converted in the style [-]d.ddde±dd where there is one digit (which is nonzero if the argument  is  nonzero)  before  the  decimal-point
              character  and the number of digits after it is equal to the precision; if the precision is missing, it is taken as 6; if the precision is zero, no decimal-point character
              appears.  An E conversion uses the letter E (rather than e) to introduce the exponent.  The exponent always contains at least two digits; if the value is zero,  the  expo‐
              nent is 00.

       f, F   The double argument is rounded and converted to decimal notation in the style [-]ddd.ddd, where the number of digits after the decimal-point character is equal to the pre‐
              cision specification.  If the precision is missing, it is taken as 6; if the precision is explicitly zero, no decimal-point character appears.  If a decimal point appears,
              at least one digit appears before it.

              (SUSv2  does  not know about F and says that character string representations for infinity and NaN may be made available.  SUSv3 adds a specification for F.  The C99 stan‐
              dard specifies "[-]inf" or "[-]infinity" for infinity, and a string starting with "nan" for NaN, in the case of f conversion, and "[-]INF" or "[-]INFINITY" or "NAN" in the
              case of F conversion.)

       g, G   The  double argument is converted in style f or e (or F or E for G conversions).  The precision specifies the number of significant digits.  If the precision is missing, 6
              digits are given; if the precision is zero, it is treated as 1.  Style e is used if the exponent from its conversion is less than -4 or greater than or equal to the preci‐
              sion.  Trailing zeros are removed from the fractional part of the result; a decimal point appears only if it is followed by at least one digit.

       a, A   (C99;  not  in SUSv2, but added in SUSv3) For a conversion, the double argument is converted to hexadecimal notation (using the letters abcdef) in the style [-]0xh.hhhhp±;
              for A conversion the prefix 0X, the letters ABCDEF, and the exponent separator P is used.  There is one hexadecimal digit before the decimal point, and the number of  dig‐
              its  after it is equal to the precision.  The default precision suffices for an exact representation of the value if an exact representation in base 2 exists and otherwise
              is sufficiently large to distinguish values of type double.  The digit before the decimal point is unspecified for nonnormalized numbers, and nonzero but otherwise unspec‐
              ified for normalized numbers.

       c      If  no  l  modifier  is  present, the int argument is converted to an unsigned char, and the resulting character is written.  If an l modifier is present, the wint_t (wide
              character) argument is converted to a multibyte sequence by a call to the wcrtomb(3) function, with a conversion state starting in the initial  state,  and  the  resulting
              multibyte string is written.

       s      If  no  l  modifier  is  present: the const char * argument is expected to be a pointer to an array of character type (pointer to a string).  Characters from the array are
              written up to (but not including) a terminating null byte ('\0'); if a precision is specified, no more than the number specified are written.  If a precision is given,  no
              null byte need be present; if the precision is not specified, or is greater than the size of the array, the array must contain a terminating null byte.

              If  an  l  modifier  is  present: the const wchar_t * argument is expected to be a pointer to an array of wide characters.  Wide characters from the array are converted to
              multibyte characters (each by a call to the wcrtomb(3) function, with a conversion state starting in the initial state before the first wide character), up to and  includ‐
              ing  a  terminating null wide character.  The resulting multibyte characters are written up to (but not including) the terminating null byte.  If a precision is specified,
              no more bytes than the number specified are written, but no partial multibyte characters are written.  Note that the precision determines the number of bytes written,  not
              the  number of wide characters or screen positions.  The array must contain a terminating null wide character, unless a precision is given and it is so small that the num‐
              ber of bytes written exceeds it before the end of the array is reached.

       C      (Not in C99 or C11, but in SUSv2, SUSv3, and SUSv4.)  Synonym for lc.  Don't use.

       S      (Not in C99 or C11, but in SUSv2, SUSv3, and SUSv4.)  Synonym for ls.  Don't use.

       p      The void * pointer argument is printed in hexadecimal (as if by %#x or %#lx).

       n      The number of characters written so far is stored into the integer pointed to by the corresponding argument.  That argument shall  be  an  int *,  or  variant  whose  size
              matches  the  (optionally)  supplied integer length modifier.  No argument is converted.  (This specifier is not supported by the bionic C library.)  The behavior is unde‐
              fined if the conversion specification includes any flags, a field width, or a precision.

       m      (Glibc extension; supported by uClibc and musl.)  Print output of strerror(errno).  No argument is required.

       %      A '%' is written.  No argument is converted.  The complete conversion specification is '%%'.

RETURN VALUE
       Upon successful return, these functions return the number of characters printed (excluding the null byte used to end output to strings).

       The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')).  If the output was truncated due to this limit, then  the
       return  value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available.  Thus, a re‐
       turn value of size or more means that the output was truncated.  (See also below under NOTES.)

       If an output error is encountered, a negative value is returned.

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌────────────────────────┬───────────────┬────────────────┐
       │Interface               │ Attribute     │ Value          │
       ├────────────────────────┼───────────────┼────────────────┤
       │printf(), fprintf(),    │ Thread safety │ MT-Safe locale │
       │sprintf(), snprintf(),  │               │                │
       │vprintf(), vfprintf(),  │               │                │
       │vsprintf(), vsnprintf() │               │                │
       └────────────────────────┴───────────────┴────────────────┘

CONFORMING TO
       fprintf(), printf(), sprintf(), vprintf(), vfprintf(), vsprintf(): POSIX.1-2001, POSIX.1-2008, C89, C99.

       snprintf(), vsnprintf(): POSIX.1-2001, POSIX.1-2008, C99.

       The dprintf() and vdprintf() functions were originally GNU extensions that were later standardized in POSIX.1-2008.

       Concerning the return value of snprintf(), SUSv2 and C99 contradict each other: when snprintf() is called with size=0 then SUSv2 stipulates an unspecified return value less  than
       1,  while  C99  allows  str to be NULL in this case, and gives the return value (as always) as the number of characters that would have been written in case the output string has
       been large enough.  POSIX.1-2001 and later align their specification of snprintf() with C99.

       glibc 2.1 adds length modifiers hh, j, t, and z and conversion characters a and A.

       glibc 2.2 adds the conversion character F with C99 semantics, and the flag character I.

NOTES
       Some programs imprudently rely on code such as the following

           sprintf(buf, "%s some further text", buf);

       to append text to buf.  However, the standards explicitly note that the results are undefined if source and  destination  buffers  overlap  when  calling  sprintf(),  snprintf(),
       vsprintf(), and vsnprintf().  Depending on the version of gcc(1) used, and the compiler options employed, calls such as the above will not produce the expected results.

       The  glibc  implementation  of  the  functions snprintf() and vsnprintf() conforms to the C99 standard, that is, behaves as described above, since glibc version 2.1.  Until glibc
       2.0.6, they would return -1 when the output was truncated.

BUGS
       Because sprintf() and vsprintf() assume an arbitrarily long string, callers must be careful not to overflow the actual space; this is often impossible to assure.  Note  that  the
       length of the strings produced is locale-dependent and difficult to predict.  Use snprintf() and vsnprintf() instead (or asprintf(3) and vasprintf(3)).

       Code  such  as  printf(foo);  often indicates a bug, since foo may contain a % character.  If foo comes from untrusted user input, it may contain %n, causing the printf() call to
       write to memory and creating a security hole.

EXAMPLE
       To print Pi to five decimal places:

           #include <math.h>
           #include <stdio.h>
           fprintf(stdout, "pi = %.5f\n", 4 * atan(1.0));

       To print a date and time in the form "Sunday, July 3, 10:02", where weekday and month are pointers to strings:

           #include <stdio.h>
           fprintf(stdout, "%s, %s %d, %.2d:%.2d\n",
                   weekday, month, day, hour, min);

       Many countries use the day-month-year order.  Hence, an internationalized version must be able to print the arguments in an order specified by the format:

           #include <stdio.h>
           fprintf(stdout, format,
                   weekday, month, day, hour, min);

       where format depends on locale, and may permute the arguments.  With the value:

           "%1$s, %3$d. %2$s, %4$d:%5$.2d\n"

       one might obtain "Sonntag, 3. Juli, 10:02".

       To allocate a sufficiently large string and print into it (code correct for both glibc 2.0 and glibc 2.1):

       #include <stdio.h>
       #include <stdlib.h>
       #include <stdarg.h>

       char *
       make_message(const char *fmt, ...)
       {
           int size = 0;
           char *p = NULL;
           va_list ap;

           /* Determine required size */

           va_start(ap, fmt);
           size = vsnprintf(p, size, fmt, ap);
           va_end(ap);

           if (size < 0)
               return NULL;

           size++;             /* For '\0' */
           p = malloc(size);
           if (p == NULL)
               return NULL;

           va_start(ap, fmt);
           size = vsnprintf(p, size, fmt, ap);
           va_end(ap);

           if (size < 0) {
               free(p);
               return NULL;
           }

           return p;
       }

       If truncation occurs in glibc versions prior to 2.0.6, this is treated as an error instead of being handled gracefully.

SEE ALSO
       printf(1), asprintf(3), puts(3), scanf(3), setlocale(3), strfromd(3), wcrtomb(3), wprintf(3), locale(5)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest version of  this  page,  can  be
       found at https://www.kernel.org/doc/man-pages/.

GNU                                                                                     2019-10-10                                                                              PRINTF(3)

]]
add_executable(IO-printf1 IO-printf1.cpp)

#[[
SCANF(3)                                                                        Linux Programmer's Manual                                                                        SCANF(3)

NAME
       scanf, fscanf, sscanf, vscanf, vsscanf, vfscanf - input format conversion

SYNOPSIS
       #include <stdio.h>

       int scanf(const char *format, ...);
       int fscanf(FILE *stream, const char *format, ...);

       // 这个函数是将一个字符串, 按照某种格式解析到几个地址当中去。
       int sscanf(const char *str, const char *format, ...);

       #include <stdarg.h>

       int vscanf(const char *format, va_list ap);
       int vsscanf(const char *str, const char *format, va_list ap);
       int vfscanf(FILE *stream, const char *format, va_list ap);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       vscanf(), vsscanf(), vfscanf():
           _ISOC99_SOURCE || _POSIX_C_SOURCE >= 200112L

DESCRIPTION
       The scanf() family of functions scans input according to format as described below.  This format may contain conversion specifications; the results from such conversions, if any,
       are stored in the locations pointed to by the pointer arguments that follow format.  Each pointer argument must be of a type that is appropriate for the  value  returned  by  the
       corresponding conversion specification.

       If the number of conversion specifications in format exceeds the number of pointer arguments, the results are undefined.  If the number of pointer arguments exceeds the number of
       conversion specifications, then the excess pointer arguments are evaluated, but are otherwise ignored.

       The scanf() function reads input from the standard input stream stdin, fscanf() reads input from the stream pointer stream, and sscanf() reads its input from the character string
       pointed to by str.

       The  vfscanf()  function is analogous to vfprintf(3) and reads input from the stream pointer stream using a variable argument list of pointers (see stdarg(3).  The vscanf() func‐
       tion scans a variable argument list from the standard input and the vsscanf() function scans it from a string; these are analogous to the vprintf(3) and vsprintf(3) functions re‐
       spectively.

       The  format  string  consists of a sequence of directives which describe how to process the sequence of input characters.  If processing of a directive fails, no further input is
       read, and scanf() returns.  A "failure" can be either of the following: input failure, meaning that input characters were unavailable, or matching failure, meaning that the input
       was inappropriate (see below).

       A directive is one of the following:

       •      A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)).  This directive matches any amount of white space, including none, in the input.

       •      An ordinary character (i.e., one other than white space or '%').  This character must exactly match the next character of input.

       •      A  conversion specification, which commences with a '%' (percent) character.  A sequence of characters from the input is converted according to this specification, and the
              result is placed in the corresponding pointer argument.  If the next item of input does not match the conversion specification, the conversion  fails—this  is  a  matching
              failure.

       Each conversion specification in format begins with either the character '%' or the character sequence "%n$" (see below for the distinction) followed by:

       •      An  optional '*' assignment-suppression character: scanf() reads input as directed by the conversion specification, but discards the input.  No corresponding pointer argu‐
              ment is required, and this specification is not included in the count of successful assignments returned by scanf().

       •      For decimal conversions, an optional quote character (').  This specifies that the input number may include thousands' separators as defined by the LC_NUMERIC category  of
              the current locale.  (See setlocale(3).)  The quote character may precede or follow the '*' assignment-suppression character.

       •      An  optional  'm'  character.  This is used with string conversions (%s, %c, %[), and relieves the caller of the need to allocate a corresponding buffer to hold the input:
              instead, scanf() allocates a buffer of sufficient size, and assigns the address of this buffer to the corresponding pointer argument, which should be a pointer to a char *
              variable (this variable does not need to be initialized before the call).  The caller should subsequently free(3) this buffer when it is no longer required.

       •      An  optional  decimal  integer which specifies the maximum field width.  Reading of characters stops either when this maximum is reached or when a nonmatching character is
              found, whichever happens first.  Most conversions discard initial white space characters (the exceptions are noted below), and these discarded characters don't  count  to‐
              ward  the  maximum  field width.  String input conversions store a terminating null byte ('\0') to mark the end of the input; the maximum field width does not include this
              terminator.

       •      An optional type modifier character.  For example, the l type modifier is used with integer conversions such as %d to  specify  that  the  corresponding  pointer  argument
              refers to a long int rather than a pointer to an int.

       •      A conversion specifier that specifies the type of input conversion to be performed.

       The  conversion specifications in format are of two forms, either beginning with '%' or beginning with "%n$".  The two forms should not be mixed in the same format string, except
       that a string containing "%n$" specifications can include %% and %*.  If format contains '%' specifications, then these correspond in order with successive pointer arguments.  In
       the  "%n$"  form (which is specified in POSIX.1-2001, but not C99), n is a decimal integer that specifies that the converted input should be placed in the location referred to by
       the n-th pointer argument following format.

   Conversions
       The following type modifier characters can appear in a conversion specification:

       h      Indicates that the conversion will be one of d, i, o, u, x, X, or n and the next pointer is a pointer to a short int or unsigned short int (rather than int).

       hh     As for h, but the next pointer is a pointer to a signed char or unsigned char.

       j      As for h, but the next pointer is a pointer to an intmax_t or a uintmax_t.  This modifier was introduced in C99.

       l      Indicates either that the conversion will be one of d, i, o, u, x, X, or n and the next pointer is a pointer to a long int or unsigned long int (rather than int), or  that
              the conversion will be one of e, f, or g and the next pointer is a pointer to double (rather than float).  Specifying two l characters is equivalent to L.  If used with %c
              or %s, the corresponding parameter is considered as a pointer to a wide character or wide-character string respectively.

       L      Indicates that the conversion will be either e, f, or g and the next pointer is a pointer to long double or the conversion will be d, i, o, u, or x and the next pointer is
              a pointer to long long.

       q      equivalent to L.  This specifier does not exist in ANSI C.

       t      As for h, but the next pointer is a pointer to a ptrdiff_t.  This modifier was introduced in C99.

       z      As for h, but the next pointer is a pointer to a size_t.  This modifier was introduced in C99.

       The following conversion specifiers are available:

       %      Matches  a  literal '%'.  That is, %% in the format string matches a single input '%' character.  No conversion is done (but initial white space characters are discarded),
              and assignment does not occur.

       d      Matches an optionally signed decimal integer; the next pointer must be a pointer to int.

       D      Equivalent to ld; this exists only for backward compatibility.  (Note: thus only in libc4.  In libc5 and glibc the %D is silently ignored, causing  old  programs  to  fail
              mysteriously.)

       i      Matches an optionally signed integer; the next pointer must be a pointer to int.  The integer is read in base 16 if it begins with 0x or 0X, in base 8 if it begins with 0,
              and in base 10 otherwise.  Only characters that correspond to the base are used.

       o      Matches an unsigned octal integer; the next pointer must be a pointer to unsigned int.

       u      Matches an unsigned decimal integer; the next pointer must be a pointer to unsigned int.

       x      Matches an unsigned hexadecimal integer; the next pointer must be a pointer to unsigned int.

       X      Equivalent to x.

       f      Matches an optionally signed floating-point number; the next pointer must be a pointer to float.

       e      Equivalent to f.

       g      Equivalent to f.

       E      Equivalent to f.

       a      (C99) Equivalent to f.

       s      Matches a sequence of non-white-space characters; the next pointer must be a pointer to the initial element of a character array that is long enough to hold the input  se‐
              quence and the terminating null byte ('\0'), which is added automatically.  The input string stops at white space or at the maximum field width, whichever occurs first.

       c      Matches  a  sequence  of  characters whose length is specified by the maximum field width (default 1); the next pointer must be a pointer to char, and there must be enough
              room for all the characters (no terminating null byte is added).  The usual skip of leading white space is suppressed.  To skip white space first, use an explicit space in
              the format.

       [      Matches  a nonempty sequence of characters from the specified set of accepted characters; the next pointer must be a pointer to char, and there must be enough room for all
              the characters in the string, plus a terminating null byte.  The usual skip of leading white space is suppressed.  The string is to be made up of characters in (or not in)
              a  particular  set;  the  set  is defined by the characters between the open bracket [ character and a close bracket ] character.  The set excludes those characters if the
              first character after the open bracket is a circumflex (^).  To include a close bracket in the set, make it the first character after the open bracket or  the  circumflex;
              any  other position will end the set.  The hyphen character - is also special; when placed between two other characters, it adds all intervening characters to the set.  To
              include a hyphen, make it the last character before the final close bracket.  For instance, [^]0-9-] means the set "everything except close bracket, zero through nine, and
              hyphen".  The string ends with the appearance of a character not in the (or, with a circumflex, in) set or when the field width runs out.

       p      Matches a pointer value (as printed by %p in printf(3); the next pointer must be a pointer to a pointer to void.

       n      Nothing  is expected; instead, the number of characters consumed thus far from the input is stored through the next pointer, which must be a pointer to int.  This is not a
              conversion and does not increase the count returned by the function.  The assignment can be suppressed with the * assignment-suppression character, but the effect  on  the
              return value is undefined.  Therefore %*n conversions should not be used.

RETURN VALUE
       On success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early match‐
       ing failure.

       The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs.  EOF is also returned if a read error occurs,
       in which case the error indicator for the stream (see ferror(3)) is set, and errno is set to indicate the error.

ERRORS
       EAGAIN The file descriptor underlying stream is marked nonblocking, and the read operation would block.

       EBADF  The file descriptor underlying stream is invalid, or not open for reading.

       EILSEQ Input byte sequence does not form a valid character.

       EINTR  The read operation was interrupted by a signal; see signal(7).

       EINVAL Not enough arguments; or format is NULL.

       ENOMEM Out of memory.

       ERANGE The result of an integer conversion would exceed the size that can be stored in the corresponding integer type.

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌─────────────────────┬───────────────┬────────────────┐
       │Interface            │ Attribute     │ Value          │
       ├─────────────────────┼───────────────┼────────────────┤
       │scanf(), fscanf(),   │ Thread safety │ MT-Safe locale │
       │sscanf(), vscanf(),  │               │                │
       │vsscanf(), vfscanf() │               │                │
       └─────────────────────┴───────────────┴────────────────┘

CONFORMING TO
       The functions fscanf(), scanf(), and sscanf() conform to C89 and C99 and POSIX.1-2001.  These standards do not specify the ERANGE error.

       The q specifier is the 4.4BSD notation for long long, while ll or the usage of L in integer conversions is the GNU notation.

       The Linux version of these functions is based on the GNU libio library.  Take a look at the info documentation of GNU libc (glibc-1.08) for a more concise description.

NOTES
   The 'a' assignment-allocation modifier
       Originally,  the  GNU C library supported dynamic allocation for string inputs (as a nonstandard extension) via the a character.  (This feature is present at least as far back as
       glibc 2.0.)  Thus, one could write the following to have scanf() allocate a buffer for an input string, with a pointer to that buffer being returned in *buf:

           char *buf;
           scanf("%as", &buf);

       The use of the letter a for this purpose was problematic, since a is also specified by the ISO C standard as a synonym for f (floating-point input).  POSIX.1-2008 instead  speci‐
       fies the m modifier for assignment allocation (as documented in DESCRIPTION, above).

       Note  that the a modifier is not available if the program is compiled with gcc -std=c99 or gcc -D_ISOC99_SOURCE (unless _GNU_SOURCE is also specified), in which case the a is in‐
       terpreted as a specifier for floating-point numbers (see above).

       Support for the m modifier was added to glibc starting with version 2.7, and new programs should use that modifier instead of a.

       As well as being standardized by POSIX, the m modifier has the following further advantages over the use of a:

       * It may also be applied to %c conversion specifiers (e.g., %3mc).

       * It avoids ambiguity with respect to the %a floating-point conversion specifier (and is unaffected by gcc -std=c99 etc.).

BUGS
       All functions are fully C89 conformant, but provide the additional specifiers q and a as well as an additional behavior of the L and l specifiers.  The latter may  be  considered
       to be a bug, as it changes the behavior of specifiers defined in C89.

       Some  combinations  of  the  type modifiers and conversion specifiers defined by ANSI C do not make sense (e.g., %Ld).  While they may have a well-defined behavior on Linux, this
       need not to be so on other architectures.  Therefore it usually is better to use modifiers that are not defined by ANSI C at all, that is, use q instead of L in combination  with
       d, i, o, u, x, and X conversions or ll.

       The usage of q is not the same as on 4.4BSD, as it may be used in float conversions equivalently to L.

EXAMPLE
       To  use the dynamic allocation conversion specifier, specify m as a length modifier (thus %ms or %m[range]).  The caller must free(3) the returned string, as in the following ex‐
       ample:

           char *p;
           int n;

           errno = 0;
           n = scanf("%m[a-z]", &p);
           if (n == 1) {
               printf("read: %s\n", p);
               free(p);
           } else if (errno != 0) {
               perror("scanf");
           } else {
               fprintf(stderr, "No matching characters\n");
           }

       As shown in the above example, it is necessary to call free(3) only if the scanf() call successfully read a string.

SEE ALSO
       getc(3), printf(3), setlocale(3), strtod(3), strtol(3), strtoul(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest version of  this  page,  can  be
       found at https://www.kernel.org/doc/man-pages/.

GNU                                                                                     2019-03-06                                                                               SCANF(3)

]]


#[[
fseek();
ftell();
rewind();

这三个函数来操作文件位置指针。

FSEEK(3)                                                          Linux Programmer's Manual                                                          FSEEK(3)

NAME
       fgetpos, fseek, fsetpos, ftell, rewind - reposition a stream.
       重新定位流(文件的文件位置指针)。
       这几个函数来操作文件位置指针。

SYNOPSIS
       #include <stdio.h>


       // 使用 fopen(); 打开一个文件, 由于打开方式的不同, 文件位置指针的指向的位置不同。
       // 有的是在文件开始, 有的是在文件结尾。
       // 而读和写都是发生在当前位置。
       //
       // 文件位置指针就是读写文件时的一个游标, 文件位置指针所指向的位置叫当前位置。

       // fseek(); 可以设置文件位置指针所指向的位置。
       int fseek(FILE *stream, long offset, int whence);

       // ftell(); 可以返回文件位置指针所指向的当前的位置在哪。
       // 请注意, 这里的返回值是 long类型。
       long ftell(FILE *stream);

       // rewind(); 相当于 fseek(stream, 0L, SEEK_SET);
       // 即将文件位置指针定位到文件的开始处。
       void rewind(FILE *stream);

       int fgetpos(FILE *stream, fpos_t *pos);

       int fsetpos(FILE *stream, const fpos_t *pos);

DESCRIPTION
       The fseek() function sets the file position indicator for the stream pointed to by stream.  The new position, measured in bytes, is obtained by adding
       offset bytes to the position specified by whence.  If whence is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to  the  start  of  the
       file,  the  current  position indicator, or end-of-file, respectively.  A successful call to the fseek() function clears the end-of-file indicator for
       the stream and undoes any effects of the ungetc(3) function on the same stream.
       fseek() 函数为 stream 指向的流设置文件位置指示符。新位置（以字节为单位）是通过将偏移字节添加到由 wherece 指定的位置获得的。
       如果 whence 设置为 SEEK_SET、SEEK_CUR 或 SEEK_END，则偏移量分别相对于文件开头、当前位置指示符或文件结尾。
       成功调用 fseek() 函数会清除流的文件结束指示符并撤消 ungetc(3) 函数对同一流的任何影响。

       The ftell() function obtains the current value of the file position indicator for the stream pointed to by stream.
       ftell() 函数获取流指向的流的文件位置指示符的当前值。

       The rewind() function sets the file position indicator for the stream pointed to by stream to the beginning of the file.  It is equivalent to:
       rewind() 函数将 stream 指向的流的文件位置指示符设置为文件的开头。它相当于:

              (void) fseek(stream, 0L, SEEK_SET)

       except that the error indicator for the stream is also cleared (see clearerr(3)).
       除了流的错误指示符也被清除（参见 clearerr(3)）。

       The fgetpos() and fsetpos() functions are alternate interfaces equivalent to ftell() and fseek() (with whence set to SEEK_SET),  setting  and  storing
       the  current  value  of the file offset into or from the object referenced by pos.  On some non-UNIX systems, an fpos_t object may be a complex object
       and these routines may be the only way to portably reposition a text stream.
       fgetpos() 和 fsetpos() 函数是等价于 ftell() 和 fseek() 的替代接口（其中 whence 设置为 SEEK_SET），
       设置和存储文件偏移量的当前值到 pos 引用的对象或从 pos 引用的对象。
       在一些非 UNIX 系统上， fpos_t 对象可能是一个复杂的对象，这些例程可能是可移植地重新定位文本流的唯一方法。

RETURN VALUE
       The rewind() function returns no value.  Upon successful completion, fgetpos(), fseek(), fsetpos() return 0, and ftell() returns the  current  offset.
       Otherwise, -1 is returned and errno is set to indicate the error.
       rewind() 函数不返回任何值。成功完成后，fgetpos()、fseek()、fsetpos() 返回 0，而 ftell() 返回当前偏移量。
       否则，返回 -1 并设置 errno 以指示错误。

ERRORS
       EINVAL The whence argument to fseek() was not SEEK_SET, SEEK_END, or SEEK_CUR.  Or: the resulting file offset would be negative.
       EINVAL fseek() 的 whence 参数不是 SEEK_SET、SEEK_END 或 SEEK_CUR。或者：生成的文件偏移量将为负数。

       ESPIPE The file descriptor underlying stream is not seekable (e.g., it refers to a pipe, FIFO, or socket).
       ESPIPE 流底层的文件描述符是不可查找的（例如，它指的是管道、FIFO 或套接字）。

       The  functions  fgetpos(), fseek(), fsetpos(), and ftell() may also fail and set errno for any of the errors specified for the routines fflush(3), fs‐
       tat(2), lseek(2), and malloc(3).
       函数 fgetpos()、fseek()、fsetpos() 和 ftell() 也可能失败并为例程 fflush(3)、fstat(2)、lseek(2)、和 malloc(3)。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).
       有关本节中使用的术语的解释，请参阅 attributes(7)。

       ┌────────────────────────────┬───────────────┬─────────┐
       │Interface                   │ Attribute     │ Value   │
       ├────────────────────────────┼───────────────┼─────────┤
       │fseek(), ftell(), rewind(), │ Thread safety │ MT-Safe │
       │fgetpos(), fsetpos()        │               │         │
       └────────────────────────────┴───────────────┴─────────┘

CONFORMING TO
       POSIX.1-2001, POSIX.1-2008, C89, C99.

SEE ALSO
       lseek(2), fseeko(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

GNU                                                                       2018-04-30                                                                 FSEEK(3)

]]

#[[
使用文件位置指针函数来计算文件的大小。
]]
add_executable(IO-CalculateFileSize2 IO-CalculateFileSize2.cpp)
#[[
fseek(); 可以帮助我们完成一个空洞文件。
空洞文件是全部为 '\0' 的文件。

空洞文件用在下载上, 一个较大的文件下载(例如: 下载文件2GB),
会在本地直接要一个2GB的空间。
将空洞文件分成多个小块, 采用多线程分开下载。
]]

#[[
fflush();

FFLUSH(3)                                                         Linux Programmer's Manual                                                         FFLUSH(3)

NAME
       fflush - flush a stream
       刷新一个流。

SYNOPSIS
       #include <stdio.h>

       int fflush(FILE *stream);

DESCRIPTION
       For  output  streams,  fflush() forces a write of all user-space buffered data for the given output or update stream via the stream's underlying write
       function.
       对于输出流， fflush() 通过流的底层写入函数强制写入给定输出或更新流的所有用户空间缓冲数据。

       For input streams associated with seekable files (e.g., disk files, but not pipes or terminals), fflush() discards any buffered  data  that  has  been
       fetched from the underlying file, but has not been consumed by the application.
       对于与可查找文件（例如，磁盘文件，但不是管道或终端）相关联的输入流，fflush() 丢弃已从底层文件中获取但尚未被应用程序使用的任何缓冲数据。

       The open status of the stream is unaffected.
       流的打开状态不受影响。

       If the stream argument is NULL, fflush() flushes all open output streams.
       如果流参数为 NULL，则 fflush() 刷新所有打开的输出流。

       For a nonlocking counterpart, see unlocked_stdio(3).
       对于非锁定副本，请参阅 unlocked_stdio(3)。

RETURN VALUE
       Upon successful completion 0 is returned.  Otherwise, EOF is returned and errno is set to indicate the error.
       成功完成后返回 0。否则，返回 EOF 并设置 errno 以指示错误。

ERRORS
       EBADF  stream is not an open stream, or is not open for writing.
       EBADF 流不是开放流，或未开放写入。

       The function fflush() may also fail and set errno for any of the errors specified for write(2).
       函数 fflush() 也可能失败并为 write(2) 指定的任何错误设置 errno。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).
       有关本节中使用的术语的解释，请参阅 attributes(7)。

       ┌──────────┬───────────────┬─────────┐
       │Interface │ Attribute     │ Value   │
       ├──────────┼───────────────┼─────────┤
       │fflush()  │ Thread safety │ MT-Safe │
       └──────────┴───────────────┴─────────┘
CONFORMING TO
       C89, C99, POSIX.1-2001, POSIX.1-2008.

       POSIX.1-2001 did not specify the behavior for flushing of input streams, but the behavior is specified in POSIX.1-2008.

NOTES
       Note  that  fflush()  flushes  only the user-space buffers provided by the C library.  To ensure that the data is physically stored on disk the kernel
       buffers must be flushed too, for example, with sync(2) or fsync(2).
       请注意， fflush() 仅刷新 C 库提供的用户空间缓冲区。为了确保数据物理存储在磁盘上，内核缓冲区也必须刷新，例如，使用 sync(2) 或 fsync(2)。

SEE ALSO
       fsync(2), sync(2), write(2), fclose(3), fileno(3), fopen(3), setbuf(3), unlocked_stdio(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

GNU                                                                       2017-09-15                                                                FFLUSH(3)



缓冲区:
    作用: 大多数情况下是好事, 缓冲区的存在最大的作用是合并系统调用。

    缓冲模式分为2种:
        1. (line buffered)行缓冲: 换行的时候( \n )刷新缓冲区, 另外满了的时候也刷新, 强制刷新。(例: 标准输出设备 stdout 是行缓冲。)
        2. (fully buffered)全缓冲: 满了的时候刷新, 强制刷新。(例如: 默认都是全缓冲模式, 终端设备除外(stdout除外))
        3. (unbuffered)无缓冲: 例如: stderr、需要立即输出的内容。

缓冲区可不可以改?
可以改。
有一个函数: setvbuf();

一个文件/设备的缓冲模式是可以改的, 默认是全缓冲模式。
绝大多数情况下, 用不到去修改缓冲模式。所以 setvbuf(); 这个函数知道有这个函数就可以了。

]]
add_executable(IO-fflush1 IO-fflush1.cpp)
add_executable(IO-fflush2 IO-fflush2.cpp)

#[[
    int fseek(FILE *stream, long offset, int whence);
    long ftell(FILE *stream);

    fseek();函数的 offset 参数类型 以及 ftell();函数的 返回值类型
    都设计成了 long 类型。

    printf( "%ld\n", LONG_MAX );
    printf( "%d\n", INT_MAX );

    9223372036854775807
    9,223,372,036,854,775,807
    2147483647
    2,147,483,647

    2147483647 / 1024 = 2,097,151.999023438 KB
    2,097,151 / 1024 = 2,047.9990234375 MB
    2,047 / 1024 = 1.9990234375 GB 将近就是 2 GB。

    9,223,372,036,854,775,807 / 1024 = 9,007,199,254,740,991.9990234375 KB
    9,007,199,254,740,991 / 1024 = 8,796,093,022,207.9990234375 MB
    8,796,093,022,207 / 1024 = 8,589,934,591.9990234375 GB
    8,589,934,591 / 1024 = 8,388,607.9990234375 TB
    8,388,607 TB

    在 32 位的电脑环境下, fseek(); 和 ftell(); 所操作的文件的大小不能超过 2 GB。
    而在 64 位的电脑环境下, 没有这个限制, 理想情况下所支持的文件大小超乎我的想象, 8,388,607 TB。

关于这两个函数有两个函数与之对应:

FSEEKO(3)                                                         Linux Programmer's Manual                                                         FSEEKO(3)

NAME
       fseeko, ftello - seek to or report file position

SYNOPSIS
       #include <stdio.h>

       int fseeko(FILE *stream, off_t offset, int whence);

       off_t ftello(FILE *stream);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       fseeko(), ftello():
           _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L
           (defining the obsolete _LARGEFILE_SOURCE macro also works)

DESCRIPTION
       The  fseeko()  and ftello() functions are identical to fseek(3) and ftell(3) (see fseek(3)), respectively, except that the offset argument of fseeko()
       and the return value of ftello() is of type off_t instead of long.
       除了 fseeko() 的偏移参数和 ftello() 的返回值是键入 off_t 而不是 long。

       On some architectures, both off_t and long are 32-bit types, but defining _FILE_OFFSET_BITS with the value 64 (before including any header files) will
       turn off_t into a 64-bit type.
       在某些体系结构上，off_t 和 long 都是 32 位类型，但是将 _FILE_OFFSET_BITS 定义为 64（在包含任何头文件之前）会将 off_t 转换为 64 位类型。

       #define _FILE_OFFSET_BITS 64


RETURN VALUE
       On  successful  completion, fseeko() returns 0, while ftello() returns the current offset.  Otherwise, -1 is returned and errno is set to indicate the
       error.
       成功完成后， fseeko() 返回 0，而 ftello() 返回当前偏移量。否则，返回 -1 并设置 errno 以指示错误。

ERRORS
       See the ERRORS in fseek(3).

VERSIONS
       These functions are available under glibc since version 2.1.
       自 2.1 版起，这些函数在 glibc 下可用。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌───────────────────┬───────────────┬─────────┐
       │Interface          │ Attribute     │ Value   │
       ├───────────────────┼───────────────┼─────────┤
       │fseeko(), ftello() │ Thread safety │ MT-Safe │
       └───────────────────┴───────────────┴─────────┘

CONFORMING TO
       POSIX.1-2001, POSIX.1-2008, SUSv2.

SEE ALSO
       fseek(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

                                                                          2017-09-15                                                                FSEEKO(3)

       int fseeko(FILE *stream, off_t offset, int whence);
       off_t ftello(FILE *stream);

       这两个函数和 fseek(); 和 ftell(); 仅仅是 long 类型改为了 off_t 类型,
       off_t是多长位的整型数, 其实我们不清楚, 有可能是 32 位, 也有可能是 64 位。
       但是 man手册 指明了告诉用户 off_t 想提供的是 64 位的整形。

       但是 fseeko(); 和 ftello(); 移植性不如 fseek(); 和 ftell(); 好。
       而且在 64 位的电脑上, fseek();和ftell();使用上就没有缺陷。

]]

#[[
如何来完整的获得一行内容?
现有的所有的函数无法读完整的一行, 因为一定有读的大小限制。
fgetc();
fputc();

fgets();
fputs();

fread();
fwrite();

scanf();
printf();

fseek();
ftell();
rewind();

fflush();


如果自己设计的话可以使用 malloc(); 配合 realloc(); 来设计出来,
例如: 我读 1024 个字节, 读满之后 realloc(); 到 2048 个字节, 然后接着读。直到读完。

有一个更好的办法: 就是使用 getline(); 函数。

getline(); 其实就是将 malloc(); 和 realloc(); 封装了一遍。


GETLINE(3)                                                                      Linux Programmer's Manual                                                                      GETLINE(3)

NAME
       getline, getdelim - delimited string input
       分隔的字符串输入。


SYNOPSIS
       #include <stdio.h>

       // 首先 malloc(); 一段空间, 然后不够了, 就扩容扩容扩容。
       lineptr: 这个函数要一个二级指针, 你不要真的实在的給这个函数传入一个二级指针。
       n: 是指的这块缓冲区的大小。
       为什么 n 被设计为了 指针类型? 因为这个函数会在内部回填 n 的值。


       ssize_t getline(char **lineptr, size_t *n, FILE *stream);

       ssize_t getdelim(char **lineptr, size_t *n, int delim, FILE *stream);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       getline(), getdelim():
           Since glibc 2.10:
               _POSIX_C_SOURCE >= 200809L
           Before glibc 2.10:
               _GNU_SOURCE

DESCRIPTION
       getline()  reads  an entire line from stream, storing the address of the buffer containing the text into *lineptr.  The buffer is null-terminated and includes the newline charac‐
       ter, if one was found.
       getline() 从流中读取一整行，将包含文本的缓冲区的地址存储到 lineptr 中。缓冲区以空字符结尾并包含换行符（如果找到的话）。

       getline();函数 从流中 读取 一整行, 把 (包含text的)缓冲区的地址(char buf[]) 存储到 *lineptr 中。
       缓冲区的大小是有第二个参数 n 指定。


       If *lineptr is set to NULL and *n is set 0 before the call, then getline() will allocate a buffer for storing the line.  This buffer should be freed by the user program  even  if
       getline() failed.
       如果在调用之前将 lineptr 设置为 NULL 并且将 n 设置为 0，则 getline() 将分配一个缓冲区来存储该行。即使 getline() 失败，该缓冲区也应由用户程序释放。

       Alternatively,  before  calling  getline(),  *lineptr can contain a pointer to a malloc(3)-allocated buffer *n bytes in size.  If the buffer is not large enough to hold the line,
       getline() resizes it with realloc(3), updating *lineptr and *n as necessary.
       或者，在调用 getline() 之前，lineptr 可以包含一个指向 malloc(3) 分配的 n 字节大小的缓冲区的指针。
       如果缓冲区不足以容纳该行，则 getline() 使用 realloc(3) 调整其大小，并根据需要更新 lineptr 和 n。

       In either case, on a successful call, *lineptr and *n will be updated to reflect the buffer address and allocated size respectively.
       在任一情况下，在成功调用时，lineptr 和 n 将被更新以分别反映缓冲区地址和分配的大小。

       getdelim() works like getline(), except that a line delimiter other than newline can be specified as the delimiter argument.  As with getline(),  a  delimiter  character  is  not
       added if one was not present in the input before end of file was reached.
       getdelim() 的工作方式与 getline() 类似，不同之处在于可以将除换行符以外的行分隔符指定为分隔符参数。
       与 getline() 一样，如果在到达文件末尾之前输入中不存在分隔符，则不会添加分隔符。

RETURN VALUE
       On  success, getline() and getdelim() return the number of characters read, including the delimiter character, but not including the terminating null byte ('\0').  This value can
       be used to handle embedded null bytes in the line read.
       成功时，getline() 和 getdelim() 返回读取的字符数，包括分隔符，但不包括终止空字节 ('\0')。此值可用于处理读取的行中嵌入的空字节。

       成功时, getline();函数返回 读取到的字符的个数, 包括分隔符( 分隔符: 空格、回车 ), 但是不包括 '\0' 字符。

       Both functions return -1 on failure to read a line (including end-of-file condition).  In the event of an error, errno is set to indicate the cause.
       两个函数都在读取一行失败时返回 -1（包括EOF条件）。如果发生错误，则设置 errno 以指示原因。

ERRORS
       EINVAL Bad arguments (n or lineptr is NULL, or stream is not valid).
       EINVAL 错误参数（n 或 lineptr 为 NULL，或流无效）。

       ENOMEM Allocation or reallocation of the line buffer failed.
       ENOMEM 行缓冲区的分配或重新分配失败。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌──────────────────────┬───────────────┬─────────┐
       │Interface             │ Attribute     │ Value   │
       ├──────────────────────┼───────────────┼─────────┤
       │getline(), getdelim() │ Thread safety │ MT-Safe │
       └──────────────────────┴───────────────┴─────────┘

CONFORMING TO(符合)
       Both getline() and getdelim() were originally GNU extensions.  They were standardized in POSIX.1-2008.
       getline() 和 getdelim() 最初都是 GNU 扩展。它们在 POSIX.1-2008 中被标准化。

       getline(); 是典型的方言中的方言。所以建议自己实现一个。

EXAMPLE
       #define _GNU_SOURCE
       #include <stdio.h>
       #include <stdlib.h>

       int
       main(int argc, char *argv[])
       {
           FILE *stream;
           char *line = NULL;
           size_t len = 0;
           ssize_t nread;

           if (argc != 2) {
               fprintf(stderr, "Usage: %s <file>\n", argv[0]);
               exit(EXIT_FAILURE);
           }

           stream = fopen(argv[1], "r");
           if (stream == NULL) {
               perror("fopen");
               exit(EXIT_FAILURE);
           }

           while ((nread = getline(&line, &len, stream)) != -1) {
               printf("Retrieved line of length %zu:\n", nread);
               fwrite(line, nread, 1, stdout);
           }

           free(line);
           fclose(stream);
           exit(EXIT_SUCCESS);
       }

SEE ALSO
       read(2), fgets(3), fopen(3), fread(3), scanf(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest version of  this  page,  can  be
       found at https://www.kernel.org/doc/man-pages/.

GNU                                                                                     2019-03-06                                                                             GETLINE(3)

]]
#[[
getline(); 是唯一一个可以实现读取一整行的函数, 无论这一整行有多长, 之前的所有函数都是不行的,
都有一个长度的限制。

但是 getline(); 是一个方言, 所以一定要自己实现一个 getline(); 函数以及 getline_free(); 函数。

]]
add_executable(IO-getline1 IO-getline1.cpp)
#[[
新版的 man手册 的一个正确的使用手法:
]]
add_executable(IO-getline2 IO-getline2.cpp)
#[[
自己实现 getline();

运行出来了, 但是有内存泄漏。
]]
add_executable(IO-getline3 IO-getline3.cpp)
#[[
改进版
]]
add_executable(IO-getline4 IO-getline4.cpp)
#[[
继续改进
还是有内存泄漏, 算了, 先到这儿把。
]]
add_executable(IO-getline5 IO-getline5.cpp)


#[[
临时文件: Temporary Files
非常具有实际意义。

临时数据放在临时文件当中, 如何创建临时文件才能不去冲突?
如何及时销毁这个临时文件? 不及时销毁的话, 一是造成内存方面吃紧, 二是可能增加命名的冲突。

当然, 临时文件命名一般是遵循规范的: 例如: 进程名_时间戳 等。

创建临时文件常用的两个函数:

    tmpnam();
    tmpfile();

TMPNAM(3)                                                         Linux Programmer's Manual                                                         TMPNAM(3)

NAME
       tmpnam, tmpnam_r - create a name for a temporary file
       为临时文件创建名称。
       为临时文件创建一个名字。

SYNOPSIS
       #include <stdio.h>

       // tmpnam(); 不能产生名字然后马上创建文件, 操作不原子。
       // 所以, 这个函数无法创建一个安全的临时文件。
       // 也正如 man手册所言: 不要使用这个函数。

       char *tmpnam(char *s);
       char *tmpnam_r(char *s);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       tmpnam_r()
           Since glibc 2.19:
               _DEFAULT_SOURCE
           Up to and including glibc 2.19:
               _BSD_SOURCE || _SVID_SOURCE

DESCRIPTION
       Note: avoid using these functions; use mkstemp(3) or tmpfile(3) instead.
       注意：避免使用这些函数；请改用 mkstemp(3) 或 tmpfile(3)。

       The tmpnam() function returns a pointer to a string that is a valid filename, and such that a file with this name did not exist at some point in time,
       so that naive programmers may think it a suitable name for a temporary file.  If the argument s is NULL, this name is generated in an internal  static
       buffer and may be overwritten by the next call to tmpnam().  If s is not NULL, the name is copied to the character array (of length at least L_tmpnam)
       pointed to by s and the value s is returned in case of success.

       The created pathname has a directory prefix P_tmpdir.  (Both L_tmpnam and P_tmpdir are defined in <stdio.h>, just like the TMP_MAX mentioned below.)

       The tmpnam_r() function performs the same task as tmpnam(), but returns NULL (to indicate an error) if s is NULL.

RETURN VALUE
       These functions return a pointer to a unique temporary filename, or NULL if a unique name cannot be generated.

ERRORS
       No errors are defined.

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌───────────┬───────────────┬──────────────────────────┐
       │Interface  │ Attribute     │ Value                    │
       ├───────────┼───────────────┼──────────────────────────┤
       │tmpnam()   │ Thread safety │ MT-Unsafe race:tmpnam/!s │
       ├───────────┼───────────────┼──────────────────────────┤
       │tmpnam_r() │ Thread safety │ MT-Safe                  │
       └───────────┴───────────────┴──────────────────────────┘
CONFORMING TO
       tmpnam(): SVr4, 4.3BSD, C89, C99, POSIX.1-2001.  POSIX.1-2008 marks tmpnam() as obsolete.

       tmpnam_r() is a nonstandard extension that is also available on a few other systems.

NOTES
       The tmpnam() function generates a different string each time it is called, up to TMP_MAX times.  If it is called more than TMP_MAX times, the behavior
       is implementation defined.

       Although  these  functions generate names that are difficult to guess, it is nevertheless possible that between the time that the pathname is returned
       and the time that the program opens it, another program might create that pathname using open(2), or create it as a symbolic link.  This can  lead  to
       security holes.  To avoid such possibilities, use the open(2) O_EXCL flag to open the pathname.  Or better yet, use mkstemp(3) or tmpfile(3).

       Portable applications that use threads cannot call tmpnam() with a NULL argument if either _POSIX_THREADS or _POSIX_THREAD_SAFE_FUNCTIONS is defined.

BUGS
       Never use these functions.  Use mkstemp(3) or tmpfile(3) instead.

SEE ALSO
       mkstemp(3), mktemp(3), tempnam(3), tmpfile(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

                                                                          2017-09-15                                                                TMPNAM(3)


TMPFILE(3)                                                        Linux Programmer's Manual                                                        TMPFILE(3)

NAME
       tmpfile - create a temporary file
       创建一个临时文件。这个临时文件没有名字。

SYNOPSIS
       #include <stdio.h>

       // 这个临时文件有没有产生, 有,
       // 但是在磁盘上看不见, 例如: ls 的时候看不见这个临时文件, ls -a 也看不见,
       // 这个临时文件不是隐藏文件。
       // 而且这个临时文件通过 fclose(); 后就销毁了。
       // 所以这个 tmpfile();函数要比 tmpnam();好用。

       FILE *tmpfile(void);

DESCRIPTION
       The tmpfile() function opens a unique temporary file in binary read/write (w+b) mode.  The file will be automatically deleted when it is closed or the
       program terminates.
       tmpfile() 函数以二进制读写 (w+b) 模式打开一个唯一的临时文件。该文件将在关闭或程序终止时自动删除。

RETURN VALUE
       The tmpfile() function returns a stream descriptor, or NULL if a unique filename cannot be generated or the unique file cannot be opened.  In the lat‐
       ter case, errno is set to indicate the error.
       tmpfile() 函数返回流描述符，如果无法生成唯一文件名或无法打开唯一文件，则返回 NULL。在后一种情况下，设置 errno 以指示错误。

ERRORS
       EACCES Search permission denied for directory in file's path prefix.
       文件路径前缀中的目录的 EACCES 搜索权限被拒绝。

       EEXIST Unable to generate a unique filename.
       EEXIST 无法生成唯一的文件名。

       EINTR  The call was interrupted by a signal; see signal(7).
       EINTR 呼叫被信号中断；见信号(7)。

       EMFILE The per-process limit on the number of open file descriptors has been reached.
       EMFILE 已达到每个进程对打开文件描述符数量的限制。

       ENFILE The system-wide limit on the total number of open files has been reached.
       ENFILE 已达到系统范围内打开文件总数的限制。

       ENOSPC There was no room in the directory to add the new filename.
       ENOSPC 目录中没有空间添加新文件名。

       EROFS  Read-only filesystem.
       EROFS 只读文件系统。

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).
       有关本节中使用的术语的解释，请参阅 attributes(7)。

       ┌──────────┬───────────────┬─────────┐
       │Interface │ Attribute     │ Value   │
       ├──────────┼───────────────┼─────────┤
       │tmpfile() │ Thread safety │ MT-Safe │
       └──────────┴───────────────┴─────────┘
CONFORMING TO
       POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD, SUSv2.

NOTES
       POSIX.1-2001 specifies: an error message may be written to stdout if the stream cannot be opened.
       POSIX.1-2001 规定：如果无法打开流，则可能会将错误消息写入 stdout。

       The  standard does not specify the directory that tmpfile() will use.  Glibc will try the path prefix P_tmpdir defined in <stdio.h>, and if that fails
       the directory /tmp.
       该标准没有指定 tmpfile() 将使用的目录。 Glibc 将尝试在 <stdio.h> 中定义的路径前缀 P_tmpdir，如果失败则目录 tmp。

SEE ALSO
       exit(3), mkstemp(3), mktemp(3), tempnam(3), tmpnam(3)

COLOPHON
       This page is part of release 5.05 of the Linux man-pages project.  A description of the project, information about reporting bugs, and the latest ver‐
       sion of this page, can be found at https://www.kernel.org/doc/man-pages/.

                                                                          2016-03-15                                                               TMPFILE(3)

]]


add_executable(IO-getline6 IO-getline6.cpp)


#[[
7 这个版本几乎要对了。
]]
add_executable(IO-getline7 IO-getline7.cpp)
#[[
8 这个版本要对了, 但是还有一点不对, 那就是如果文件的最后一行不是单独的一行, 就会不返回最后一行读了多少个字节。

这个缺陷在 9 的版本进行改正。
]]
add_executable(IO-getline8 IO-getline8.cpp)

#[[
todo 注意: 笔记: 虽然上一行只有3个字符, 但是上一行所占的是 3 + 2 = 5 个字节。2: (CRLF: \r\n)。请注意！
 注意: 文件的编码方式以及文件的 line separator(行分隔符) 方式。
 一般使用 UTF-8 和 CRLF。
 这样的话一个文件的大小(字节数)就是 = 字符数(如果是中文的话是3个字节) + 多少个CRLF(一个换行就是一个CRLF) * 2
 EOF(end of file)是一个文件的最后一个有效字符的下一个位置。

9 版本完成了任务, 设计成功了。10 版本是完成设计后的第一个版本。
]]
add_executable(IO-getline9 IO-getline9.cpp)
add_executable(IO-getline10 IO-getline10.cpp)
